home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.04 Apr 89 / Scroller Code / Scroll.c next >
Encoding:
C/C++ Source or Header  |  1988-12-15  |  23.7 KB  |  981 lines  |  [TEXT/KAHL]

  1. /* Scrolling Manager Library of Subroutines
  2.     © 1988 John A. Nairn, All Rights Reserved
  3.  
  4.     This library of routines allow any application to
  5.     easily implement scrolling in any window. The library
  6.     can handle application-defined graphic windows as well
  7.     as Text Edit windows.
  8.  
  9.     General variables appearing as common parameters
  10.         1. theScrlp: the ScrollPtr for scrolling window
  11.         2. theWindow: window pointer to scrolling window
  12.     
  13.     Routines marked “internal use” should not need to be
  14.         called by the application
  15.         
  16.     WARNING: A number of these routines assume scrolling
  17.         is occurring in the active window. This means
  18.         that ScrollActivate() must have been called
  19.         before calling these routines. Failure to do so
  20.         may result in system crash.    
  21. */
  22.  
  23. #include <MacTypes.h>                /*    Includes    */
  24. #include <QuickDraw.h>
  25. #include <ControlMgr.h>
  26. #include <TextEdit.h>
  27. #include "ScrollMgr.h"
  28. #define Active 0                    /* defines */
  29. #define Inactive 255
  30. #define NIL 0L
  31.  
  32. ScrollPtr scrlp;                    /* Global Variables */
  33. int scrollAmt,scrollCode,scrollType,linesVis,lineSize;
  34. int vJoySpeed=8;hJoySpeed=8;
  35. pascal Boolean SMClikLoop();
  36.  
  37. /* Initialize ScollInfo data record    for new window and
  38.         return ScrollPtr as the function return. Note
  39.         this routine calls ScrollActivate() to activate
  40.         the scroll bars.
  41.     1. theScrlp: pointer to use for ScrollInfo or NIL to
  42.                     put ScrollInfo in heap
  43.     2. textWindow=TRUE if Text Edit window else =FALSE
  44.     3. v or hLineSize: pixels per line to scroll (0 to
  45.                     not include scroll bar)
  46.     4. v or hTotalLines: number of lines in document
  47.     5. v or hTools: width of tool bars in pixels (0 if
  48.                     no tool bar)
  49.     6. v or hRuler: width of rulers in pixels (0 if no
  50.                     ruler)
  51.     7. vScrollTop or hScrollLeft: scroll bar margins
  52.     8. sRefCon: ScrollInfo refCon     */
  53.  
  54. ScrollPtr SetScrollWindow(theWindow,theScrlp,textWindow,
  55.                 vLineSize,vTotalLines,vTools,vRuler,
  56.                 vScrollTop,hLineSize,hTotalLines,hTools,
  57.                 hRuler,hScrollLeft,sRefCon)
  58.     WindowPtr theWindow;
  59.     ScrollPtr theScrlp;
  60.     Boolean textWindow;
  61.     int vLineSize,vTotalLines,vTools,vRuler;
  62.     int vScrollTop,hLineSize,hTotalLines,hTools;
  63.     int hRuler,hScrollLeft;
  64.     long sRefCon;
  65. {
  66.     ScrollPtr newscrlp;
  67.     Rect viewRect,scrollRect;
  68.  
  69.     if(theScrlp==NIL)    
  70.         newscrlp=(ScrollInfo *)
  71.                     NewPtr((Size)sizeof(ScrollInfo));
  72.     else
  73.         newscrlp=theScrlp;
  74.     
  75.     /*    vertical scoll bar initialization    */
  76.     newscrlp->vScrollMarg=vScrollTop;
  77.     newscrlp->vRectTopLeft.v=hTools+hRuler;
  78.     newscrlp->vRectTopLeft.h=vTools;
  79.     if(vLineSize!=0)
  80.     {    SetVertRect(newscrlp,theWindow,vLineSize,
  81.                         hLineSize);
  82.         scrollRect=theWindow->portRect;
  83.         scrollRect.left=scrollRect.right-SBarWidth;
  84.         scrollRect.right+=1;
  85.         scrollRect.bottom-=14;
  86.         scrollRect.top-=1-newscrlp->vScrollMarg;
  87.         newscrlp->vScrollHdl=NewControl(theWindow,
  88.             &scrollRect,"\p",1,0,0,0,scrollBarProc,
  89.             (long)vLineSize);
  90.         SetScroll(newscrlp,vTotalLines,VertBar);
  91.     }
  92.     else
  93.         newscrlp->vScrollHdl=NIL;
  94.         
  95.     /*    horizontal scoll bar initialization    */
  96.     newscrlp->hScrollMarg=hScrollLeft;
  97.     newscrlp->hRectTopLeft.v=hTools;
  98.     newscrlp->hRectTopLeft.h=vTools+vRuler;
  99.     if(hLineSize!=0)
  100.     {    SetHorizRect(newscrlp,theWindow,hLineSize,
  101.                         vLineSize);
  102.         scrollRect=theWindow->portRect;
  103.         scrollRect.left-=1-newscrlp->hScrollMarg;
  104.         scrollRect.right-=SBarWidth-1;
  105.         scrollRect.top=scrollRect.bottom-SBarWidth;
  106.         scrollRect.bottom+=1;
  107.         newscrlp->hScrollHdl=NewControl(theWindow,
  108.             &scrollRect,"\p",1,0,0,0,scrollBarProc,
  109.             (long)(-hLineSize));
  110.         SetScroll(newscrlp,hTotalLines,HorizBar);
  111.     }
  112.     else
  113.         newscrlp->hScrollHdl=NIL;
  114.  
  115.     /*    Text edit initialization (if text window)    */    
  116.     if(textWindow)
  117.     {    ScrollSectRect(newscrlp,theWindow,&viewRect);
  118.         newscrlp->hTE=TENew(&viewRect,&viewRect);
  119.         SetClikLoop(&SMClikLoop,newscrlp->hTE);
  120.     }
  121.     else    
  122.         newscrlp->hTE=NIL;
  123.  
  124.     newscrlp->refCon=sRefCon;
  125.     ScrollActivate(newscrlp);    
  126.     return(newscrlp);
  127. }
  128.  
  129. /*    Set the scrolling rectangles - internal use */
  130.  
  131. SetVertRect(newscrlp,theWindow,theLineSize,hasHorizBar)
  132.     ScrollPtr newscrlp;
  133.     WindowPtr theWindow;
  134.     int theLineSize,hasHorizBar;
  135. {
  136.     Rect r;
  137.     
  138.     r=theWindow->portRect;
  139.     r.left+=newscrlp->vRectTopLeft.h;
  140.     r.top+=newscrlp->vRectTopLeft.v;
  141.     r.right-=SBarWidth;
  142.     if(hasHorizBar)
  143.         r.bottom-=SBarWidth;
  144.     newscrlp->vertScrollRect=r;
  145.     newscrlp->vertLinesVis=(r.bottom-r.top)/theLineSize;
  146. }
  147.  
  148. SetHorizRect(newscrlp,theWindow,theLineSize,hasVertBar)
  149.     ScrollPtr newscrlp;
  150.     WindowPtr theWindow;
  151.     int theLineSize,hasVertBar;
  152. {
  153.     Rect r;
  154.     
  155.     r=theWindow->portRect;
  156.     r.left+=newscrlp->hRectTopLeft.h;
  157.     r.top+=newscrlp->hRectTopLeft.v;
  158.     r.bottom-=SBarWidth;
  159.     if(hasVertBar)
  160.         r.right-=SBarWidth;
  161.     newscrlp->horizScrollRect=r;
  162.     newscrlp->horizLinesVis=(r.right-r.left)/theLineSize;
  163. }
  164.  
  165. /*    Call when window activates: will activate scroll bars
  166.         and set internal pointer scrlp to newscrlp which
  167.         is ScrollPtr for window being activated    */
  168.  
  169. ScrollActivate(newscrlp)
  170.     ScrollPtr newscrlp;
  171. {
  172.     scrlp=newscrlp;
  173.     if(scrlp->vScrollHdl!=NIL)
  174.         HiliteControl(scrlp->vScrollHdl,Active);
  175.     if(scrlp->hScrollHdl!=NIL)
  176.         HiliteControl(scrlp->hScrollHdl,Active);
  177. }
  178.  
  179. /*    Call when window deactivates: will deactivate scroll
  180.         bars. oldscrlp is ScrollPtr for deactivating
  181.         window */
  182.  
  183. ScrollDeactivate(oldscrlp)
  184.     ScrollPtr oldscrlp;
  185. {
  186.     if(oldscrlp->vScrollHdl!=NIL)
  187.         HiliteControl(oldscrlp->vScrollHdl,Inactive);
  188.     if(oldscrlp->hScrollHdl!=NIL)
  189.         HiliteControl(oldscrlp->hScrollHdl,Inactive);
  190. }
  191.  
  192. /*    Call when scrolling window changes size.
  193.          Note: assumes growing window is active window */
  194.  
  195. GrowScroll(theWindow)
  196.     WindowPtr theWindow;
  197. {
  198.     int theLineSize,hasOtherBar;
  199.     int newTop,newRight,newBottom,newLeft;
  200.     Rect tempRect;
  201.     
  202.     if(scrlp->vScrollHdl!=NIL)
  203.     {    /*    Move vertical Bar */
  204.         newTop=theWindow->portRect.top-1+
  205.                             scrlp->vScrollMarg;
  206.         newRight=theWindow->portRect.right-SBarWidth;
  207.         newBottom=theWindow->portRect.bottom-SBarWidth;
  208.         MoveControl(scrlp->vScrollHdl,newRight,newTop);
  209.         SizeControl(scrlp->vScrollHdl,SBarWidth+1,
  210.                             newBottom-newTop+1);
  211.         
  212.         /*    Reset vertical scrolling rectangle */
  213.         theLineSize=GetCRefCon(scrlp->vScrollHdl);
  214.         hasOtherBar=(scrlp->hScrollHdl!=NIL)?TRUE:FALSE;
  215.         SetVertRect(scrlp,theWindow,theLineSize,
  216.                             hasOtherBar);
  217.         
  218.         /*    Reset vertical scroll bar range */
  219.         SetScroll(scrlp,scrlp->vertLines,VertBar);
  220.     }
  221.     
  222.     if(scrlp->hScrollHdl!=NIL)
  223.     {    /*    Move horizontal Bar */
  224.         newTop=theWindow->portRect.bottom-SBarWidth;
  225.         newLeft=theWindow->portRect.left-1+
  226.                                 scrlp->hScrollMarg;
  227.         newRight=theWindow->portRect.right-SBarWidth;
  228.         MoveControl(scrlp->hScrollHdl,newLeft,newTop);
  229.         SizeControl(scrlp->hScrollHdl,newRight-newLeft+1,
  230.                             SBarWidth+1);
  231.     
  232.         /*    Reset vertical scrolling rectangle */
  233.         theLineSize=-GetCRefCon(scrlp->hScrollHdl);
  234.         hasOtherBar=(scrlp->vScrollHdl!=NIL)?TRUE:FALSE;
  235.         SetHorizRect(scrlp,theWindow,theLineSize,
  236.                             hasOtherBar);
  237.         
  238.         /*    Reset vertical scroll bar range */
  239.         SetScroll(scrlp,scrlp->horizLines,HorizBar);
  240.     }
  241.     
  242.     /*    Reset view rectangle (if text window) */    
  243.     if(scrlp->hTE!=NIL)
  244.     {    ScrollSectRect(scrlp,theWindow,&tempRect);
  245.         (**scrlp->hTE).viewRect=tempRect;
  246.     }
  247. }
  248.  
  249. /*    Invalidate the scroll bar area before and after
  250.         window resizing */
  251.  
  252. InvalBars(theWindow)
  253.     WindowPtr theWindow;
  254. {
  255.     Rect r;
  256.     
  257.     r=theWindow->portRect;        /*Horizontal ScrollBar*/
  258.     r.top=r.bottom-SBarWidth;
  259.     InvalRect(&r);
  260.     r.top=theWindow->portRect.top; /*Vertical Scroll Bar*/
  261.     r.left=r.right-SBarWidth;
  262.     InvalRect(&r);
  263. }
  264.  
  265. /*    Reset a scroll bar range when the document changes
  266.       size. Updates window if necessary. 
  267.         1. totalLines: total Lines in document
  268.         2. barType: VertBar or HorizBar    */
  269.  
  270. SetScroll(theScrlp,totalLines,barType)
  271.     ScrollPtr theScrlp;
  272.     int totalLines,barType;
  273. {
  274.     int n,max,currentValue,numLinesVis,tempLineSize,units;
  275.     WindowPtr ctrlWindow;
  276.     ControlHandle scrollHdl;
  277.     
  278.     if(barType==VertBar)
  279.     {    tempLineSize=GetCRefCon(theScrlp->vScrollHdl);
  280.         numLinesVis=theScrlp->vertLinesVis;
  281.         scrollHdl=theScrlp->vScrollHdl;
  282.         theScrlp->vertLines=totalLines;
  283.     }
  284.     else
  285.     {    tempLineSize=-GetCRefCon(theScrlp->hScrollHdl);
  286.         numLinesVis=theScrlp->horizLinesVis;
  287.         scrollHdl=theScrlp->hScrollHdl;
  288.         theScrlp->horizLines=totalLines;
  289.     }
  290.     
  291.     n=totalLines-numLinesVis;
  292.     currentValue=GetCtlValue(scrollHdl);
  293.     max=(n>0 ? n : 0);
  294.     SetCtlMax(scrollHdl,max);
  295.     
  296.     /* if necessary, scroll and redraw the window    */
  297.     if(currentValue>max)
  298.     {    ctrlWindow=(*scrollHdl)->contrlOwner;
  299.         InvalRect(&ctrlWindow->portRect);
  300.         if(theScrlp->hTE!=NIL)
  301.         {    units=tempLineSize*(currentValue-max);    
  302.             if(barType==VertBar)
  303.                 OffsetRect(&(**theScrlp->hTE).destRect,
  304.                             0,units);
  305.             else
  306.                 OffsetRect(&(**theScrlp->hTE).destRect,
  307.                             units,0);
  308.         }
  309.     }
  310. }
  311.  
  312. /*    Return current margins in pixels or in scrolling
  313.       lines for window.
  314.         1. left or topMargin: margin returned in
  315.                 these variables
  316.         2. lm or tmType: set to inPixels (0) or
  317.                 inLines (1) for result in pixels
  318.                 or lines    */
  319.  
  320. GetMargins(theScrlp,leftMargin,lmType,topMargin,tmType)
  321.     ScrollPtr theScrlp;
  322.     int *leftMargin,*topMargin,lmType,tmType;
  323. {
  324.     int theLineSize;
  325.     
  326.     if(theScrlp->vScrollHdl!=NIL)
  327.     {    *topMargin=GetCtlValue(theScrlp->vScrollHdl);
  328.         if(tmType==inPixels)
  329.         {    theLineSize=GetCRefCon(theScrlp->vScrollHdl);
  330.             *topMargin*=theLineSize;
  331.         }
  332.     }
  333.     else
  334.         *topMargin=0;
  335.     if(theScrlp->hScrollHdl!=NIL)
  336.     {    *leftMargin=GetCtlValue(theScrlp->hScrollHdl);
  337.         if(lmType==inPixels)
  338.         {    theLineSize=-GetCRefCon(theScrlp->hScrollHdl);
  339.             *leftMargin*=theLineSize;
  340.         }
  341.     }
  342.     else
  343.         *leftMargin=0;
  344. }
  345.  
  346. /*    Find intersection of two scrolling rectangles, if no
  347.      scroll bars, this rect will include the grow box 
  348.         1. drawRect: pointer to resulting rectangle - this
  349.               pointer also returned as function value    */
  350.  
  351. Rect *ScrollSectRect(theScrlp,theWindow,drawRect)
  352.     ScrollPtr theScrlp;
  353.     WindowPtr theWindow;
  354.     Rect *drawRect;
  355. {
  356.     NonScrollRect(theScrlp,theWindow,drawRect);
  357.     drawRect->top=theScrlp->vRectTopLeft.v;
  358.     if(theScrlp->hRectTopLeft.v>drawRect->top)
  359.         drawRect->top=theScrlp->hRectTopLeft.v;
  360.     drawRect->left=theScrlp->vRectTopLeft.h;
  361.     if(theScrlp->hRectTopLeft.h>drawRect->left)
  362.         drawRect->left=theScrlp->hRectTopLeft.h;
  363.     return(drawRect);
  364. }
  365.  
  366. /*    Return handle for region that is intersection of two
  367.     scrolling rectangles. If no scroll bars, region will
  368.     exclude grow box    */
  369.  
  370. RgnHandle ScrollSectRgn(theScrlp,theWindow)
  371.     ScrollPtr theScrlp;
  372.     WindowPtr theWindow;
  373. {
  374.     Rect r;
  375.     RgnHandle drawRgn,tempRgn;
  376.     
  377.     ScrollSectRect(theScrlp,theWindow,&r);
  378.     drawRgn=NewRgn();
  379.     RectRgn(drawRgn,&r);
  380.     if((theScrlp->vScrollHdl==NIL)&&
  381.             (theScrlp->hScrollHdl==NIL))
  382.     {    tempRgn=NewRgn();
  383.         r.left=theWindow->portRect.right-SBarWidth;
  384.         r.top=theWindow->portRect.bottom-SBarWidth;
  385.         r.right=theWindow->portRect.right;
  386.         r.bottom=theWindow->portRect.bottom;
  387.         RectRgn(tempRgn,&r);
  388.         DiffRgn(drawRgn,tempRgn,drawRgn);
  389.         DisposeRgn(tempRgn);
  390.     }
  391.     return(drawRgn);
  392. }
  393.  
  394. /*    Calculate rectangle that excludes the scroll bars
  395.         1. drawRect: pointer to resulting rectangle - this
  396.              pointer also returned as function value    */
  397.  
  398. Rect *NonScrollRect(theScrlp,theWindow,drawRect)
  399.     ScrollPtr theScrlp;
  400.     WindowPtr theWindow;
  401.     Rect *drawRect;
  402. {
  403.     *drawRect=theWindow->portRect;
  404.     if(theScrlp->vScrollHdl!=NIL)
  405.         drawRect->right-=SBarWidth;
  406.     if(theScrlp->hScrollHdl!=NIL)
  407.         drawRect->bottom-=SBarWidth;
  408.     return(drawRect);
  409. }
  410.  
  411. /*    Draw enough grow icon to enclose active scroll bars */
  412.  
  413. ScrollDrawGrowIcon(theScrlp,theWindow)
  414.     ScrollPtr theScrlp;
  415.     WindowPtr theWindow;
  416. {
  417.     Rect r;
  418.     RgnHandle tempRgn;
  419.     
  420.     GetClip(tempRgn=NewRgn());
  421.     r=theWindow->portRect;
  422.     if(theScrlp->vScrollHdl==NIL)
  423.         r.top=r.bottom-SBarWidth;
  424.     if(theScrlp->hScrollHdl==NIL)
  425.         r.left=r.right-SBarWidth;
  426.     ClipRect(&r);
  427.     DrawGrowIcon(theWindow);
  428.     SetClip(tempRgn);
  429.     DisposeRgn(tempRgn);
  430. }
  431.  
  432. /*    Action procedure for scrolling    - internal use
  433.     Scroll by scrollAmt (set by doScroll)
  434.     ScrollCode is the part of the scroll bar being tracked
  435.     (set by doScroll) ScrollType is type of scroll bar
  436.     (set by doScroll)
  437.     May also be called for tracking selections. In this
  438.         case scrollType will be set by setSelectScroll,
  439.         scrollAmt will be 1 or -1 (set by selectScroll)
  440.         and scrollCode will be set to 0. */
  441.  
  442. pascal void ScrollProc(control,theCode)
  443.     ControlHandle control;
  444.     int theCode;
  445. {
  446.     int max,oldValue,newValue;
  447.     WindowPtr ctrlWindow=(*control)->contrlOwner;
  448.     
  449.     if(theCode==scrollCode)
  450.     {    oldValue=GetCtlValue(control);
  451.         newValue=oldValue+scrollAmt;
  452.         if(newValue<0) newValue=0;
  453.         max=GetCtlMax(control);
  454.         if(newValue>max) newValue=max;
  455.         SetCtlValue(control,newValue);
  456.         ThumbMove(ctrlWindow,oldValue,newValue);
  457.     }
  458. }
  459.  
  460. /*    Do scrolling, return TRUE if scrolled or FALSE if not 
  461.         1. where: mouse location in Global coordinates
  462.     Note: assumes scrolling in current active window */
  463.  
  464. DoScroll(theWindow,where)
  465.     WindowPtr theWindow;
  466.     long where;
  467. {
  468.     int partCode,oldValue,newValue;
  469.     ControlHandle control;
  470.     
  471.     GlobalToLocal(&where);
  472.     partCode=FindControl(where,theWindow,&control);
  473.     if(partCode==0)      /*mouse down not in scroll bar*/
  474.         return(FALSE);
  475.         
  476.     lineSize=GetCRefCon(control);
  477.     if(lineSize<0)            /* horiz scrolling    */
  478.     {    linesVis=scrlp->horizLinesVis;
  479.         scrollType=HorizBar;
  480.         lineSize=-lineSize;
  481.     }
  482.     else                    /* vert scrolling    */
  483.     {    linesVis=scrlp->vertLinesVis;
  484.         scrollType=VertBar;
  485.     }
  486.         
  487.     switch(partCode)
  488.     {    case inUpButton:
  489.         case inDownButton:
  490.         case inPageUp:
  491.         case inPageDown:
  492.             switch(partCode)
  493.             {    case inUpButton:
  494.                     scrollAmt=-1;
  495.                     break;
  496.                 case inDownButton:
  497.                     scrollAmt=1;
  498.                     break;
  499.                 case inPageUp:
  500.                     scrollAmt=-linesVis;
  501.                     break;
  502.                 case inPageDown:
  503.                     scrollAmt=linesVis;
  504.                     break;
  505.             }
  506.             scrollCode=partCode;
  507.             TrackControl(control,where,&ScrollProc);
  508.             break;
  509.         case inThumb:
  510.             oldValue=GetCtlValue(control);
  511.             if(TrackControl(control,where,-1L))
  512.             {    newValue=GetCtlValue(control);
  513.                 ThumbMove(theWindow,oldValue,newValue);
  514.             }
  515.             break;
  516.         default:
  517.             break;
  518.     }
  519.     return(TRUE);
  520. }
  521.  
  522. /*    Set to prepare for automatic scrolling of scroll bars 
  523.         - internal use */
  524.  
  525. SetSelectScroll(control)
  526.     ControlHandle control;
  527. {
  528.     lineSize=GetCRefCon(control);
  529.     if(lineSize<0)            /* horiz scrolling    */
  530.     {    linesVis=scrlp->horizLinesVis;
  531.         scrollType=HorizBar;
  532.         lineSize=-lineSize;
  533.     }
  534.     else                    /* vert scrolling    */
  535.     {    linesVis=scrlp->vertLinesVis;
  536.         scrollType=VertBar;
  537.     }
  538.     scrollCode=0;
  539. }        
  540.  
  541. /*    Scroll dir lines using scroll bar set by
  542.         setSelectScroll - internal use */
  543.  
  544. SelectScroll(dir)
  545.     int dir;
  546. {
  547.     scrollAmt=dir;
  548.     if(scrollType==HorizBar)
  549.         ScrollProc(scrlp->hScrollHdl,0);
  550.     else
  551.         ScrollProc(scrlp->vScrollHdl,0);
  552. }
  553.  
  554. /*    Scroll along with mouse while mouse button is down 
  555.         1. where: mouse location in Global coordinates
  556.     Note: assumes scrolling in current active window */
  557.  
  558. DragScroll(where)
  559.     Point where;
  560. {
  561.     WindowPtr theWindow;
  562.     register int vLineSize=0,hLineSize=0,vAmt,hAmt;
  563.     Rect dragRect;
  564.     Point lastWhere;
  565.     
  566.     if(scrlp->vScrollHdl!=NIL)    
  567.     {    theWindow=(*(scrlp->vScrollHdl))->contrlOwner;
  568.         vLineSize=GetCRefCon(scrlp->vScrollHdl);
  569.     }
  570.     if(scrlp->hScrollHdl!=NIL)
  571.     {    theWindow=(*(scrlp->hScrollHdl))->contrlOwner;
  572.         hLineSize=-GetCRefCon(scrlp->hScrollHdl);
  573.     }
  574.     if((vLineSize==0)&&(hLineSize==0)) return;
  575.         
  576.     ScrollSectRect(scrlp,theWindow,&dragRect);
  577.     GlobalToLocal(&where);
  578.     if(!PtInRect(where,&dragRect)) return;
  579.     lastWhere=where;
  580.     while(StillDown())
  581.     {    GetMouse(&where);
  582.         if(PtInRect(where,&dragRect))
  583.         {    if(vLineSize>0)            /* vert scrolling    */
  584.             {    if(vAmt=(lastWhere.v-where.v)/vLineSize)
  585.                 {    SetSelectScroll(scrlp->vScrollHdl);
  586.                     SelectScroll(vAmt);
  587.                     lastWhere.v-=vAmt*vLineSize;
  588.                 }
  589.             }
  590.             if(hLineSize>0)            /* horiz scrolling    */
  591.             {    if(hAmt=(lastWhere.h-where.h)/hLineSize)
  592.                 {    SetSelectScroll(scrlp->hScrollHdl);
  593.                     SelectScroll(hAmt);
  594.                     lastWhere.h-=hAmt*hLineSize;
  595.                 }
  596.             }
  597.         }
  598.     }
  599. }
  600.  
  601. /*    Do joystick scrolling as long as mouse is down
  602.         1. where: mouse location in Global coordinates
  603.     Note: assumes scrolling in current active window */
  604.  
  605. JoyStickScroll(where)
  606.     Point where;
  607. {
  608.     int vAmt,hAmt;
  609.     Point newWhere;
  610.  
  611.     if((scrlp->vScrollHdl==NIL)&&(scrlp->hScrollHdl==NIL))
  612.         return;    
  613.     GlobalToLocal(&where);
  614.     while(StillDown())
  615.     {    GetMouse(&newWhere);
  616.         vAmt=(newWhere.v-where.v)/vJoySpeed;
  617.         if((scrlp->vScrollHdl!=NIL)&&vAmt)
  618.         {    SetSelectScroll(scrlp->vScrollHdl);
  619.             SelectScroll(vAmt);
  620.         }
  621.         hAmt=(newWhere.h-where.h)/hJoySpeed;
  622.         if((scrlp->hScrollHdl!=NIL)&&hAmt)
  623.         {    SetSelectScroll(scrlp->hScrollHdl);
  624.             SelectScroll(hAmt);
  625.         }
  626.     }
  627. }
  628.  
  629. /*    Set joy stick speed in pixels per speed increment 
  630.         1. v or hSpeed: vertical or horizontal settings */
  631.  
  632. SetJoySpeed(vSpeed,hSpeed)
  633.     int vSpeed,hSpeed;
  634. {
  635.     vJoySpeed=vSpeed;
  636.     hJoySpeed=hSpeed;
  637. }
  638.  
  639. /*    If mouse is outside content region, scroll 1 line
  640.        towards mouse location and return TRUE,
  641.        otherwise just return FALSE
  642.     Note: assumes scrolling in current active window    */
  643.  
  644. FollowMouse()
  645. {
  646.     Point where;
  647.     RgnHandle tempRgn;
  648.     int followed=FALSE;
  649.     
  650.     GetMouse(&where);
  651.     GetClip(tempRgn=NewRgn());
  652.     ClipRect(&thePort->portRect);
  653.     
  654.     if(scrlp->hScrollHdl!=NIL)        /* horiz tracking */
  655.     {    if(where.h<scrlp->horizScrollRect.left)
  656.         {    SetSelectScroll(scrlp->hScrollHdl);
  657.             SelectScroll(-1);
  658.             followed=TRUE;
  659.         }
  660.         else if(where.h>scrlp->horizScrollRect.right)
  661.         {    SetSelectScroll(scrlp->hScrollHdl);
  662.             SelectScroll(1);
  663.             followed=TRUE;
  664.         }
  665.     }
  666.     if(scrlp->vScrollHdl!=NIL)        /* vert tracking */
  667.     {    if(where.v<scrlp->vertScrollRect.top)
  668.         {    SetSelectScroll(scrlp->vScrollHdl);
  669.             SelectScroll(-1);
  670.             followed=TRUE;
  671.         }
  672.         else if(where.v>scrlp->vertScrollRect.bottom)
  673.         {    SetSelectScroll(scrlp->vScrollHdl);
  674.             SelectScroll(1);
  675.             followed=TRUE;
  676.         }
  677.     }
  678.     
  679.     SetClip(tempRgn);
  680.     DisposeRgn(tempRgn);
  681.     return(followed);
  682. }
  683.  
  684. /*    Handle automatic scrolling of Text Edit Windows
  685.     Note: assumes scrolling in current active window */
  686.  
  687. pascal Boolean SMClikLoop()
  688. {
  689.     Point where;
  690.     RgnHandle tempRgn;
  691.     
  692.     GetMouse(&where);
  693.     if(PtInRect(where,&(**scrlp->hTE).viewRect))
  694.         return(TRUE);
  695.     GetClip(tempRgn=NewRgn());
  696.     ClipRect(&thePort->portRect);
  697.     
  698.     if(scrlp->hScrollHdl!=NIL)        /* horiz tracking */
  699.     {    if(where.h<(**scrlp->hTE).viewRect.left)
  700.         {    SetSelectScroll(scrlp->hScrollHdl);
  701.             SelectScroll(-1);
  702.         }
  703.         else if(where.h>(**scrlp->hTE).viewRect.right)
  704.         {    SetSelectScroll(scrlp->hScrollHdl);
  705.             SelectScroll(1);
  706.         }
  707.     }
  708.     if(scrlp->vScrollHdl!=NIL)        /* vert tracking */
  709.     {    if(where.v<(**scrlp->hTE).viewRect.top)
  710.         {    SetSelectScroll(scrlp->vScrollHdl);
  711.             SelectScroll(-1);
  712.         }
  713.         else if(where.v>(**scrlp->hTE).viewRect.bottom)
  714.         {    SetSelectScroll(scrlp->vScrollHdl);
  715.             SelectScroll(1);
  716.         }
  717.     }
  718.     
  719.     SetClip(tempRgn);    /* must restore clip region */
  720.     DisposeRgn(tempRgn);
  721.     return(TRUE);
  722. }
  723.  
  724. /*    Scroll window from oldValue to newValue
  725.         - internal use */
  726.  
  727. ThumbMove(theWindow,oldValue,newValue)
  728.     WindowPtr theWindow;
  729.     int oldValue,newValue;
  730. {
  731.     int units=oldValue-newValue;
  732.     
  733.     if(units)
  734.         ScrollWindow(theWindow,units);
  735. }
  736.  
  737. /*    Do the actual scrolling. When required this routine
  738.     calls UpdateWindow() which must be supplied by the
  739.     application - internal use */
  740.  
  741. ScrollWindow(theWindow,units)
  742.     WindowPtr theWindow;
  743.     int units;
  744. {
  745.     int absunits,rectLength;
  746.     Boolean hasRuler=FALSE;
  747.     RgnHandle tmpRgn;
  748.     GrafPtr saveport;
  749.     Rect rulerRect;
  750.     
  751.     GetPort(&saveport);
  752.     SetPort(theWindow);
  753.     absunits= units<0 ? -units : units;
  754.     
  755.     /* scroll text windows    */
  756.     if(scrlp->hTE!=NIL)
  757.     {    if(scrollType==HorizBar)
  758.         {    TEScroll(rectLength=lineSize*units,0,
  759.                             scrlp->hTE);
  760.             if(scrlp->vRectTopLeft.v!=
  761.                             scrlp->hRectTopLeft.v)
  762.             {    hasRuler=TRUE;
  763.                 rulerRect.left=scrlp->hRectTopLeft.h;
  764.                 rulerRect.top=scrlp->hRectTopLeft.v;
  765.                 rulerRect.bottom=scrlp->vRectTopLeft.v;
  766.                 rulerRect.right=
  767.                             scrlp->horizScrollRect.right;
  768.             }
  769.         }
  770.         else
  771.         {    TEScroll(0,rectLength=lineSize*units,
  772.                             scrlp->hTE);
  773.             if(scrlp->vRectTopLeft.h!=
  774.                             scrlp->hRectTopLeft.h)
  775.             {    hasRuler=TRUE;
  776.                 rulerRect.left=scrlp->vRectTopLeft.h;
  777.                 rulerRect.top=scrlp->vRectTopLeft.v;
  778.                 rulerRect.right=scrlp->hRectTopLeft.h;
  779.                 rulerRect.bottom=
  780.                             scrlp->vertScrollRect.bottom;
  781.             }
  782.         }
  783.         /*    if rulers in text windows, scroll them    */
  784.         if(hasRuler)
  785.         {    tmpRgn=NewRgn();
  786.             if(scrollType==HorizBar)
  787.                 ScrollRect(&rulerRect,lineSize*units,0,
  788.                             tmpRgn);
  789.             else
  790.                 ScrollRect(&rulerRect,0,lineSize*units,
  791.                             tmpRgn);
  792.             InvalRgn(tmpRgn);
  793.             DisposeRgn(tmpRgn);
  794.         }
  795.     }
  796.     
  797.     /*    Scolling more than 1 page in graphic windows */ 
  798.     else if(absunits>linesVis)
  799.     {    if(scrollType==HorizBar)
  800.             InvalRect(&scrlp->horizScrollRect);
  801.         else
  802.             InvalRect(&scrlp->vertScrollRect);
  803.     }
  804.     
  805.     /*    Fractional page scolling in graphic windows    */
  806.     else
  807.     {    tmpRgn=NewRgn();
  808.         if(scrollType==HorizBar)
  809.             ScrollRect(&scrlp->horizScrollRect,
  810.                         lineSize*units,0,tmpRgn);
  811.         else
  812.             ScrollRect(&scrlp->vertScrollRect,
  813.                         0,lineSize*units,tmpRgn);
  814.         InvalRgn(tmpRgn);
  815.         DisposeRgn(tmpRgn);
  816.     }
  817.     
  818.     /*    If required, call Update process    */
  819.     if((scrlp->hTE==NIL)||hasRuler)
  820.         UpdateWindow(theWindow,scrollType);
  821.         
  822.     SetPort(saveport);
  823. }
  824.  
  825. /*    Scroll the line and column numbers given by selLine
  826.         and selColumn into view
  827.     Note: assumes scrolling in current active window */
  828.  
  829. FixInsertPt(selLine,selColumn)
  830.     int selLine,selColumn;
  831. {
  832.     if(scrlp->vScrollHdl!=NIL)
  833.         MoveInsertPt(selLine,VertBar);
  834.     if(scrlp->hScrollHdl!=NIL)
  835.         MoveInsertPt(selColumn,HorizBar);
  836. }
  837.  
  838. /*    Scroll begining of selection of Text Edit window into
  839.        view
  840.     Note: assumes scrolling in current active window */
  841.  
  842. FixTEInsertPt()
  843. {
  844.     int selLine,selColumn=0,textLength,*line0;
  845.     WindowPtr TEWindow;
  846.     GrafPtr saveGraf;
  847.     register int thePt,jumpSize,lineLook;
  848.  
  849.     if(scrlp->hTE==NIL) return;
  850.     if(scrlp->vScrollHdl!=NIL)    
  851.         TEWindow=(*(scrlp->vScrollHdl))->contrlOwner;
  852.     else if(scrlp->hScrollHdl!=NIL)
  853.         TEWindow=(*(scrlp->hScrollHdl))->contrlOwner;
  854.     else
  855.         return;
  856.  
  857.     /*    Binary search for current line */
  858.     thePt=(**scrlp->hTE).selStart;        /*Set up pointers*/
  859.     lineLook=(**scrlp->hTE).nLines;
  860.     line0=&(**scrlp->hTE).lineStarts[0];
  861.     if(thePt>=*(line0+lineLook))        /*Check last line*/
  862.         selLine=lineLook-1;
  863.     else
  864.     {    jumpSize=lineLook>>1|1;        /*div by 2, but not 0*/
  865.         lineLook-=jumpSize;
  866.         while(jumpSize=jumpSize>>1|1)    /*reduce jumpsize*/
  867.         {    if(thePt<*(line0+lineLook))
  868.                 lineLook-=jumpSize;        /*look back*/
  869.             else if(thePt>=*(line0+lineLook+1))
  870.                 lineLook+=jumpSize;        /*look forward*/
  871.             else
  872.             {    selLine=lineLook;        /*found line*/
  873.                 break;
  874.             }
  875.         }
  876.     }
  877.  
  878.     /*    Find column by getting width of text from start of
  879.         line to insertion point.    */
  880.     if(scrlp->hScrollHdl!=NIL)
  881.     {    GetPort(&saveGraf);
  882.         SetPort(TEWindow);
  883.         HLock((**scrlp->hTE).hText);
  884.         textLength=thePt-
  885.                     (**scrlp->hTE).lineStarts[selLine];
  886.         selColumn=TextWidth(*((**scrlp->hTE).hText),
  887.                     (**scrlp->hTE).lineStarts[selLine],
  888.                     textLength);
  889.         HUnlock((**scrlp->hTE).hText);
  890.         selColumn/=(-GetCRefCon(scrlp->hScrollHdl));
  891.         SetPort(saveGraf);
  892.     }
  893.  
  894.     /* Correct selLine in case scrolling line is smaller
  895.             than text lineHeight */
  896.     if(GetCRefCon(scrlp->vScrollHdl)<
  897.                         (**scrlp->hTE).lineHeight)
  898.     {    selLine=selLine*(**scrlp->hTE).lineHeight/
  899.                         GetCRefCon(scrlp->vScrollHdl);
  900.         if(selLine>GetCtlValue(scrlp->vScrollHdl))
  901.             selLine+=1+((**scrlp->hTE).lineHeight/
  902.                         GetCRefCon(scrlp->vScrollHdl));
  903.     }
  904.     FixInsertPt(selLine,selColumn);
  905. }
  906.  
  907. /*    Scoll one direction to bring point into view
  908.         - internal use */
  909.  
  910. MoveInsertPt(selStart,barType)
  911.     int selStart,barType;
  912. {
  913.     int curValue,theLinesVis,units;
  914.     ControlHandle scrollHdl;
  915.  
  916.     if(barType==VertBar)
  917.     {    theLinesVis=scrlp->vertLinesVis;
  918.         scrollHdl=scrlp->vScrollHdl;
  919.     }
  920.     else
  921.     {    theLinesVis=scrlp->horizLinesVis;
  922.         scrollHdl=scrlp->hScrollHdl;
  923.     }
  924.     
  925.     curValue=GetCtlValue(scrollHdl);
  926.     if(selStart<curValue)
  927.         units=selStart-curValue;
  928.     else if(selStart>(curValue+theLinesVis-1))
  929.         units=selStart-curValue-theLinesVis+1;
  930.     else
  931.         return;
  932.     
  933.     SetSelectScroll(scrollHdl);
  934.     SelectScroll(units);
  935. }
  936.  
  937. /*    Call TEClick - call from here insures SMClikLoop Code
  938.         available. Meaning of parameters identical to
  939.         Toolbox routine TEClick() */
  940.  
  941. ScrollTEClick(where,theShift,hTE)
  942.     Point where;
  943.     Boolean theShift;
  944.     TEHandle hTE;
  945. {
  946.     TEClick(where,theShift,hTE);
  947. }
  948.  
  949. /*    If ScrollInfo in heap, dispose of pointer when done.
  950.         Do not call if ScrollInfo not in heap*/
  951.  
  952. DisposeScroll(theScrlp)
  953.     ScrollPtr theScrlp;
  954. {
  955.     DisposPtr(theScrlp);
  956. }
  957.  
  958. /*    Return the refCon in ScrollInfo    record */
  959.  
  960. long GetSRefCon(theScrlp)
  961.     ScrollPtr theScrlp;
  962. {
  963.     return(theScrlp->refCon);
  964. }
  965.  
  966. /*    Set the refCon in ScrollInfo    record */
  967.  
  968. SetSRefCon(theScrlp,sRefCon)
  969.     ScrollPtr theScrlp;
  970.     long sRefCon;
  971. {
  972.     theScrlp->refCon=sRefCon;
  973. }
  974.  
  975. /*    Return the current active ScrollPtr    */
  976.  
  977. ScrollPtr ActiveScrollPtr()
  978. {
  979.     return(scrlp);
  980. }
  981.